package com.springlearn.springsourcecode.chap5;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.Map;
import java.util.Set;

/**
 * @author wtcode
 * @Description  将@Configuration和@Component注解的类中的@Bean的方法创建bean并注入到容器中
 * @date 2025/3/28 - 15:32
 */
public class AtBeanPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        try {

            CachingMetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
            String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
            for (String beanDefinitionName : beanDefinitionNames) {
                BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName);
                MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(beanDefinition.getBeanClassName());

                AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
                if(isConfigurationClass(annotationMetadata)){
                    processBeanMethods(beanDefinitionName,metadataReader,beanFactory);
                }


            }




        } catch (IOException e) {
            e.printStackTrace();
        }


    }

    private boolean isConfigurationClass(AnnotationMetadata annotationMetadata){
        if(annotationMetadata.hasMetaAnnotation(Configuration.class.getName()) || annotationMetadata.hasMetaAnnotation(Component.class.getName())){
            return true;
        }else {
            return false;
        }
    }

    public void processBeanMethods(String beanDefinitionName,MetadataReader metadataReader, ConfigurableListableBeanFactory beanFactory ){
        // 获取所有@Bean注解的方法
        Set<MethodMetadata> methods = metadataReader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());

        for (MethodMetadata method : methods) {

            String methodName = method.getMethodName();
            if(beanFactory.containsBeanDefinition(methodName)){
                continue;
            }

            BeanDefinitionBuilder bd = BeanDefinitionBuilder.genericBeanDefinition();
            bd.setFactoryMethodOnBean(methodName,beanDefinitionName);
            bd.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);



            Map<String, Object> attris = method.getAnnotationAttributes(Bean.class.getName());
            if(attris!=null){
                String initMethod = (String) attris.get("initMethod");
                if(!StringUtils.isEmpty(initMethod)){
                    bd.setInitMethodName(initMethod);
                }

                String destoryMethod = (String) attris.get("destroyMethod");
                if(!StringUtils.isEmpty(destoryMethod)){
                    bd.setDestroyMethodName(destoryMethod);
                }
            }

            AbstractBeanDefinition beanDefinition = bd.getBeanDefinition();

            ((DefaultListableBeanFactory) beanFactory).registerBeanDefinition(methodName,beanDefinition);

        }



    }

}
